//Handles encryption logic


use rotor::Rotor;
use setup;


pub struct Dailies {

    pub order: Vec<u8>,             // rotors to be used, in order
    pub rotations: Vec<u8>,         // rotations of the rings
    pub indicators: Vec<u8>,        // start positions of the 3 rotors
    pub plugboard: Vec<u8>,         // plugboard connections (6)
    pub reflector: Vec<u8>         // reflector connections (13)
}

impl Dailies {
    pub fn new(key: Vec<String>) -> Dailies {
        let order = setup::parse_order(key[0].clone());
        let rotations = setup::parse_order(key[1].clone());
        let indicators = setup::parse_indicator(key[2].clone());
        let plugboard = setup::parse_pairs(key[3].clone());
        let reflector = setup::parse_pairs(key[4].clone());

        Dailies {
            order: order,
            rotations: rotations,
            indicators: indicators,
            plugboard: plugboard,
            reflector: reflector,
        }
    }
}


// enigma struct:
// contains entire machine state in one struct
// contains encrypt function which takes a single char as input, and mutates the entire struct.
// the only states that actually change are the rotors
pub struct Enigma {
            pub rotor: Vec<Rotor>, // rotors in use, in correct order
            pub plugboard: Vec<u8>,
            pub reflector: Vec<u8>,
}
       
impl Enigma {

    pub fn new(
        rotor_set: Vec<String>,      // vector of all 5 rotors 
        dailies: Dailies,
        ) -> Enigma {
 
        
        let mut used_rotors: Vec<Rotor> = Vec::new();
        for i in 0 .. 3 {
            used_rotors.push(Rotor::new(rotor_set[dailies.order[i] as usize].as_ref(), dailies.rotations[i]));
            for _j in 0 .. dailies.indicators[i] as usize {
                used_rotors[i].step();
            }
        }

        Enigma {
            rotor: used_rotors,
            plugboard: dailies.plugboard,
            reflector: dailies.reflector,
        }
    }

    //encrypt a single character

    pub fn encrypt(&mut self, input:char) -> char {
        //convert input to u8, do bitmath and delete if not alphabetical

    //calculate rotor steps
        if self.rotor[1].notch == 0 {
            self.rotor[2].step();
            self.rotor[1].step();
        }
        if self.rotor[0].notch == 0 {
            self.rotor[1].step();
        }
        self.rotor[0].step();

    //convert input to u8 for transfer through rotors

        let mut charval: u8 = input as u8 - 65;

    //pass through plugboard

        charval = self.plugboard[charval as usize];

    //pass through rotors, right to left
    
        for i in 0 .. 3 {
            charval = self.rotor[i].leftalph[charval as usize];
        }

    //reflector
        
        charval = self.reflector[charval as usize];

    // left to right journey through rotors
    
        for i in (0 .. 3).rev() {
            let mut x = false;
            for j in 0 .. 26 {
                if charval == self.rotor[i].leftalph[j] as u8 {
                    charval = j as u8;
                    x = true;
                    break
                }
            }
            if x == false {
                //print curent enigma state
                panic!("no match for character on left to right journey!");
            }
        }

        charval = self.plugboard[charval as usize];

    (   charval + 65) as char
    }
}

// This is real sloppy. Does rust really not have 'and' ????

pub fn filter_chars (input:Vec<char>) -> Vec<char> {
    let mut output:Vec<char> = Vec::new();
    for c in input {
        let u = c as u8;
        if u >= 65 {
            if u <=90 {
                output.push(c);
                }
            else if u >= 97 {
                if u <= 122{
                    output.push((u -32) as char );
                }
            }
        }
    }
    output
}
